<?php
declare (strict_types=1);

namespace app\course\logic\base\admin;

use app\admin\logic\system\Log;
use app\common\event\subscribes\attach\Attach as AttachSubscribes;
use app\common\exception\LogicException;
use app\common\helper\util\Tool;
use app\common\library\Excel;
use app\common\logic\Attach;
use app\common\model\payment\PaymentOrder as PO;
use app\common\model\payment\PaymentOrderItem as POI;
use app\course\model\base\admin\CourseStudent as CourseStudentModel;
use app\course\model\base\Course;
use app\course\model\base\CourseSection;
use app\course\model\classes\admin\ClassesLink;
use app\course\model\record\admin\LearnCourseFinished;
use app\course\model\record\admin\LearnCourseRecord;
use app\user\logic\user\admin\Account;
use think\facade\Event;
use think\facade\Request;

/**
 * 课程学员
 */
class CourseStudent extends CourseStudentModel
{
    /**
     * 获取课程学员列表
     * Author   Martinsun<syh@sunyonghong.com>
     * Date 2020-06-30
     *
     * @param int   $course_id [description]
     * @param array $map       [description]
     * @return   [type]                                    [description]
     */
    public function getList(int $course_id, array $map = [], string $phone = '', $course_type = 1)
    {
        $builder = $this->with(['user']);
        if ($phone) {
            // $user_id = Account::withoutGlobalScope(['mhm'])->where('phone', $phone)->removeOption('soft_delete')->value('id');

            $user_id = Account::where('phone', $phone)->removeOption('soft_delete')->value('id');

            $builder = $builder->where('user_id', $user_id);
        }

        return $builder->where('course_id', $course_id)->where($map)->paginate($this->getListRows())->each(function ($item) use ($course_id, $course_type) {
            $user_id = $item->user_id;
            if ($course_type == 1) {
                $this->paddingLearnData($item, $user_id, $course_id);
            } else if ($course_type == 4) {
                $this->paddingClassesLearnData($item, $user_id, $course_id);
            }
        });
    }

    /**
     * 添加学员
     * Author   Martinsun<syh@sunyonghong.com>
     * Date 2020-06-30
     *
     * @param int    $course_id [description]
     * @param string $phone     [description]
     */
    public function addStudent(int $course_id, string $phone)
    {
        if (!$course_id || !$phone) {
            throw new LogicException('添加学员失败');
        }

        // 获取课程信息
        /** @var Course $course */
        $course = app(Course::class)->findOrEmpty($course_id);
        if ($course->isEmpty()) {
            throw new LogicException('课程数据错误');
        }
        if ($course->course_type == 2 && $course->course_live_type == 2 && $course->limit_buy_count) {
            $count = $this->where('course_id', $course_id)->count();
            if ($count && $count >= $course->limit_buy_count) {
                throw new LogicException('学员已满员');
            }
        }
        // 课程有效期
        if ($course->term_time > 9999 && Request::time() > $course->term_time) {
            throw new LogicException('课程有效期已经过期，无法继续添加学员');
        }
        // 学员是否存在
        $user = Account::withoutGlobalScope(['mhm'])
            ->where('mhm_id', request()->mhm_id)
            ->where('phone', $phone)
            ->find();
        if (!$user) {
            throw new LogicException('添加的学员不存在');
        }
        // 课程中是否有该学员
        $courseStudent = $this->where(['course_id' => $course_id, 'user_id' => $user->id])->findOrEmpty();
        if (!$courseStudent->isEmpty() && (!$courseStudent->getData('expire_time') || $courseStudent->getData('expire_time') > Request::time())) {
            throw new LogicException('课程中已存在该学员');
        }

        $termTime = $course->getData('term_time') === 0 ? null : $course->getData('term_time');
        if ($termTime) {
            $termTime = $termTime <= 9999 ? strtotime('+' . $termTime . ' day') : $termTime;
        }

        $courseStudent->course_id   = $course_id;
        $courseStudent->user_id     = $user->id;
        $courseStudent->from        = 1;
        $courseStudent->expire_time = $termTime;

        if (!$courseStudent->save()) {
            throw new LogicException('添加学员失败');
        }
        $title = $user->nick_name . '，' . $user->phone;
        Log::write('将学员【' . $title . '】添加到课程【' . $course->title . '】', 'course_student', 'create', true);

        return $this;
    }

    /**
     * 移除学员
     * Author   Martinsun<syh@sunyonghong.com>
     * Date 2020-06-30
     *
     * @param int $course_id   [description]
     * @param int $student_id  [description]
     * @param int $course_type [description]
     * @return   [type]                                      [description]
     */
    public function removeStudent(int $course_id, int $student_id, int $course_type)
    {
        // 查询课程学员信息
        $student = $this->with(['course', 'user'])->where('user_id', $student_id)->whereCourseId($course_id)->findOrFail();
        // 来源检测: 如果是通过购买支付加入的学员,则需要修改订单
        $from = $student->getAttr('from');
        if ($from === 2 || $from === 3) {
            // 查询子订单表中的主订单
            $order_no = POI::where('user_id', $student_id)->where('product_type_id', $course_type)->where('product_id', $course_id)->value('order_no');
            if (!$order_no) {
                throw new LogicException('支付订单号异常，无法移除');

            }
            // 查询主订单
            $order = PO::where('order_no', $order_no)->findOrEmpty();
            if ($order->isEmpty()) {
                throw new LogicException('支付订单号异常，无法移除');
            }

            if ($order->getAttr('status') != '20') {
                throw new LogicException('支付订单号已退款或处于退款中，无法移除');
            }

            $this->startTrans();
            try {
                $order->status = '70';

                if (!$order->save()) {
                    throw new LogicException('订单状态修改失败，暂时不能移除，请重试');
                }

                if (!$student->delete()) {
                    throw new LogicException('学员移除失败');
                }

                $title = $student->user->nick_name . '，' . $student->user->phone;

                Log::write('将学员【' . $title . '】从课程【' . $student->title . '】中移除', 'course_student', 'delete', true);

                $this->commit();

            } catch (LogicException $e) {
                $this->rollback();
                throw $e;
            }
        } else {
            if (!$student->delete()) {
                throw new LogicException('学员移除失败');
            }
            $title = $student->user->nick_name . '，' . $student->user->phone;

            Log::write('将学员【' . $title . '】从课程【' . $student->title . '】中移除', 'course_student', 'delete', true);
        }
    }

    /**
     * 根据用户ID获取已经加入的课程列表
     * Author   Martinsun<syh@sunyonghong.com>
     * Date 2020-07-31
     *
     * @param int $user_id [description]
     * @return   [type]                                  [description]
     */
    public function getCourseListByUserId(int $user_id)
    {
        $data = $this->with(['course'])->where('user_id', $user_id)->paginate($this->getListRows())->each(function ($item) use ($user_id) {
            if ($item->course_type == 1 || $item->course_type == 2) {
                $this->paddingLearnData($item, $user_id, $item->course_id);
            } else if ($item->course_type == 4) {
                $this->paddingClassesLearnData($item, $user_id, $item->course_id);
            }
        });

        return $data;
    }

    /**
     * 填充学习数据
     * Author   Martinsun<syh@sunyonghong.com>
     * Date 2020-07-31
     *
     * @param    [type]                         $item      [description]
     * @param    [type]                         $user_id   [description]
     * @param    [type]                         $course_id [description]
     * @return   [type]                                    [description]
     */
    protected function paddingLearnData($item, $user_id, $course_id)
    {
        // 学习状态
        // 是否学习完成
        $finished = $this->isLearnFinished($user_id, $course_id);

        // 课时总数
        $item->course_section_count = $this->getCourseSectionCount($course_id);
        if ($finished) {
            $item->learn_status_text   = '已完成';
            $item->learn_section_count = $item->course_section_count;
        } else {
            // 是否开始学习
            $learn_count             = $this->getCourseLearnCount($user_id, $course_id);
            $item->learn_status_text = $learn_count == 0 ? '未开始' : '学习中';
            // 正在学习的课时数
            $item->learn_section_count = $learn_count;

        }

        $item->learn_rate = $item->learn_section_count . ' / ' . $item->course_section_count;

        // 总学习时长
        $total_time       = $this->getCourseLearnTotalTime($user_id, $course_id);
        $item->total_time = $total_time > 0 ? Tool::secsToStr($total_time) : '-';

        // 最近学习时间
        $lately            = $this->getCourseLatelyTime($user_id, $course_id);
        $item->lately_time = $lately ? date('Y-m-d H:i', $lately) : '-';

        return $item;
    }

    /**
     * 班级课学习记录数据
     * Author   Martinsun<syh@sunyonghong.com>
     * Date 2020-08-04
     *
     * @param    [type]                         $item      [description]
     * @param    [type]                         $user_id   [description]
     * @param    [type]                         $course_id [description]
     * @return   [type]                                    [description]
     */
    protected function paddingClassesLearnData($item, $user_id, $course_id)
    {
        // 查询当前班级课有哪些课程
        $courses                    = ClassesLink::where('classes_id', $course_id)->column('course_id');
        $item->course_section_count = count($courses);
        // 已经学完的课程
        $item->learn_section_count = LearnCourseFinished::where('user_id', $user_id)->whereIn('course_id', $courses)->count();

        $item->learn_rate = $item->learn_section_count . ' / ' . $item->course_section_count;

        // 总学习时长
        $total_time       = $this->getCourseLearnTotalTime($user_id, $courses);
        $item->total_time = $total_time > 0 ? Tool::secsToStr($total_time) : '-';
        if ($item->learn_section_count == $item->course_section_count) {
            $item->learn_status_text = '已完成';
        } else {
            // 是否开始学习
            $item->learn_status_text = $total_time > 0 ? '学习中' : '未开始';
            $item->total_time_sec    = $total_time;
        }

        // 最近学习时间
        $lately            = $this->getCourseLatelyTime($user_id, $courses);
        $item->lately_time = $lately ? date('Y-m-d H:i', $lately) : '-';

        return $item;

    }

    /**
     * 课程是否学完
     * Author   Martinsun<syh@sunyonghong.com>
     * Date 2020-07-31
     *
     * @param    [type]                         $user_id   [description]
     * @param    [type]                         $course_id [description]
     * @return   boolean                                   [description]
     */
    public function isLearnFinished($user_id, $course_id)
    {
        return LearnCourseFinished::where('user_id', $user_id)->where('course_id', $course_id)->find() ? true : false;
    }

    /**
     * 课程课时总数
     * Author   Martinsun<syh@sunyonghong.com>
     * Date 2020-07-31
     *
     * @param    [type]                         $course_id [description]
     * @return   [type]                                    [description]
     */
    public function getCourseSectionCount($course_id)
    {
        return CourseSection::where('course_id', $course_id)
            ->where('is_last', 1)
            ->where('status', 1)
            ->count();
    }

    /**
     * 正在学习的课时数量
     * Author   Martinsun<syh@sunyonghong.com>
     * Date 2020-07-31
     *
     * @param    [type]                         $user_id   [description]
     * @param    [type]                         $course_id [description]
     * @return   [type]                                    [description]
     */
    public function getCourseLearnCount($user_id, $course_id)
    {
        $course_id = is_numeric($course_id) ? [$course_id] : $course_id;

        return LearnCourseRecord::where('user_id', $user_id)->whereIn('course_id', $course_id)->count();
    }

    /**
     * 课程学习时长
     * Author   Martinsun<syh@sunyonghong.com>
     * Date 2020-07-31
     *
     * @param    [type]                         $user_id   [description]
     * @param    [type]                         $course_id [description]
     * @return   [type]                                    [description]
     */
    public function getCourseLearnTotalTime($user_id, $course_id)
    {
        $course_id = is_numeric($course_id) ? [$course_id] : $course_id;

        return LearnCourseRecord::where('user_id', $user_id)->whereIn('course_id', $course_id)->sum('total_time');
    }

    /**
     * 课程最近学习时间
     * Author   Martinsun<syh@sunyonghong.com>
     * Date 2020-07-31
     *
     * @param    [type]                         $user_id   [description]
     * @param    [type]                         $course_id [description]
     * @return   [type]                                    [description]
     */
    public function getCourseLatelyTime($user_id, $course_id)
    {
        $course_id = is_numeric($course_id) ? [$course_id] : $course_id;

        return LearnCourseRecord::where('user_id', $user_id)->whereIn('course_id', $course_id)->order('update_time', 'desc')->value('update_time');
    }

    /**
     * 导入学员
     * Author   Martinsun<syh@sunyonghong.com>
     * Date 2020-08-10
     *
     * @param int $course_id [description]
     * @param int $attach_id [description]
     * @return   [type]                                    [description]
     */
    public function doImportStudent(int $course_id, int $attach_id)
    {
        // 获取课程信息
        $course = app(Course::class)->findOrEmpty($course_id);
        if ($course->isEmpty()) {
            throw new LogicException('课程数据错误');
        }

        // 课程有效期
        if ($course->term_time > 9999 && Request::time() > $course->term_time) {
            throw new LogicException('课程有效期已经过期，无法继续添加学员');
        }
        // 是否限制购买
        $limit      = false;
        $rest_count = 0;

        if ($course->course_type == 2 && $course->course_live_type == 2 && $course->limit_buy_count) {
            $limit      = true;
            $count      = $this->where('course_id', $course_id)->count();
            $rest_count = $course->limit_buy_count - ($count ?: 0);
        }

        // 获取附件信息
        $attach = Attach::where('id', $attach_id)->findOrEmpty();
        if ($attach->isEmpty()) {
            throw new LogicException('附件不存在，请重新上传');
        }

        $filepath = $attach->filepath;
        if (!is_file($filepath)) {
            throw new LogicException('附件不存在，请重新上传');

        }
        // 加载附件内容
        $data = Excel::import($filepath);
        unset($data[0]);
        // 导入数据的数量
        $importCount = count($data);
        // 课程限制人数
        if ($limit && $importCount > $rest_count) {
            throw new LogicException('当前课程学员数量限制导入' . $rest_count . '人，请删减学员号重新导入');
        }
        // 单次最多导入1000条数据
        if ($importCount > 1000) {
            throw new LogicException('单次最多导入1000条数据');
        }

        $data  = array_column($data, '0');
        $datas = array_chunk($data, 200);
        $total = 0;
        $error = [];
        $users = [];
        // 检查数据是否正确,超过10条错误数据,则不允许导入
        foreach ($datas as $phones) {
            $exits = Account::withoutGlobalScope(['mhm'])
                ->where('mhm_id', request()->mhm_id)
                ->whereIn('phone', $phones)
                ->column('phone', 'id');
            $users += $exits;
            $diff  = array_diff($phones, $exits);
            $count = count($diff);
            if ($count > 0) {
                $error = $error + $diff;
            }
            $total += $count;

            if ($total >= 10) {
                break;
            }

        }

        if ($total > 0) {
            $error = array_slice($error, 0, 10);
            $txt   = $total > 10 ? '等' : '';
            // 有错误
            throw new LogicException('手机号【' . implode('，', $error) . '】' . $txt . '用户不存在，请先创建用户或检查导入数据');
        }
        // 批量添加
        $inserts  = [];
        $time     = Request::time();
        $termTime = $course->getData('term_time') === 0 ? null : $course->getData('term_time');
        if ($termTime) {
            $termTime = $termTime <= 9999 ? strtotime('+' . $termTime . ' day') : $termTime;
        }
        foreach ($users as $user_id => $phone) {
            $courseStudent = $this->where(['course_id' => $course_id, 'user_id' => $user_id])->findOrEmpty();
            if (!$courseStudent->isEmpty() && (!$courseStudent->getData('expire_time') || $courseStudent->getData('expire_time') > Request::time())) {
                throw new LogicException('课程中已存在学员【' . $phone . '】');
            }
            $add = [
                'from'        => 1,
                'create_time' => $time,
                'user_id'     => $user_id,
                'course_id'   => $course_id,
                'expire_time' => $termTime
            ];
            if (!$courseStudent->isEmpty()) {
                $add['id'] = $courseStudent->id;
            }
            $inserts[] = $add;
        }

        if (empty($inserts)) {
            // 删除附件
            Event::subscribe(AttachSubscribes::class);
            Event::trigger('AttachTrueDeleted', $attach_id);

            throw new LogicException("导入失败，请检查是否重复导入");
        }
        // $max     = $this->max('id');
        // $success = $this->extra('IGNORE')->insertAll($inserts, 250);
        $success      = $this->saveAll($inserts);
        $successCount = count($success);
        if ($successCount == 0) {
            // 删除附件
            Event::subscribe(AttachSubscribes::class);
            Event::trigger('AttachTrueDeleted', $attach_id);

            throw new LogicException("导入失败，请检查是否重复导入");
        }

        // $users = $this->where('id', '>', $max)->limit($success)->column('user_id');

        Log::write('导入附件【' . $attach->filename . '】中的学员到课程【' . $course->title . '】', 'course_student', 'create', true);

        // 删除附件
        Event::subscribe(AttachSubscribes::class);
        Event::trigger('AttachTrueDeleted', $attach_id);

        return [
            'total'   => $importCount,
            'success' => $successCount,
            'exists'  => $importCount - $successCount,
        ];
    }

    /**
     * 获取导出数据
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/9/2
     *
     * @param int $courseId
     * @param int $course_type
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getExportData(int $courseId, int $courseType)
    {
        $datas  = $this->with(['user', 'course'])->where('course_id', $courseId)->select();
        $xdatas = [];
        $title  = '';
        foreach ($datas as $k => $data) {
            !$k && $title = $data->title;
            $user_id = $data->user_id;
            if ($courseType == 1) {
                $this->paddingLearnData($data, $user_id, $courseId);
            } else if ($courseType == 4) {
                $this->paddingClassesLearnData($data, $user_id, $courseId);
            }
            if ($data->user) {
                $xdatas[] = [
                    'phone'             => $data->user->phone,
                    'learn_rate'        => $data->learn_rate,
                    'total_time'        => $data->total_time,
                    'lately_time'       => $data->lately_time,
                    'learn_status_text' => $data->learn_status_text,
                    'from_text'         => $data->from_text,
                    'create_time'       => $data->create_time
                ];
            }
        }

        Log::write('导出课程【' . $title . '】中的学员', 'course_student', 'create', true);

        return $xdatas;
    }

    /**
     * 给学员批量添加课程
     *
     * @param int   $userId
     * @param array $courseIds
     * @return \think\Collection
     * @throws \Exception
     */
    public function addCourse(int $userId, array $courseIds)
    {
        $datas        = [];
        $studentCount = [];
        foreach ($courseIds as $courseId) {
            // 是否已经存在
            $id = $this->where(['course_id' => $courseId, 'user_id' => $userId])->value('id');
            if ($id) {
                continue;
            }

            // 获取课程信息
            /** @var Course $course */
            $course   = app(Course::class)->findOrEmpty($courseId);
            $termTime = $course->getData('term_time') === 0 ? null : $course->getData('term_time');
            if ($termTime) {
                $termTime = $termTime <= 9999 ? strtotime('+' . $termTime . ' day') : $termTime;
            }

            // 学员数量超员判断
            if ($course->course_type == 2 && $course->course_live_type == 2 && $course->limit_buy_count) {
                if (!isset($studentCount[$courseId])) {
                    $count = $this->where('course_id', $courseId)->count();
                } else {
                    $count = $studentCount[$courseId];
                }

                if ($count && $count >= $course->limit_buy_count) {
                    continue;
                }

                $studentCount[$courseId] = $count + 1;
            }

            $add = [
                'course_id'   => $courseId,
                'user_id'     => $userId,
                'from'        => 1,
                'expire_time' => $termTime,
                'create_time' => Request::time()
            ];

            $datas[] = $add;
        }

        unset($studentCount);

        if (empty($datas)) {
            throw new LogicException('无新课程添加，检查是否重复添加课程');
        }

        return $this->saveAll($datas);

    }
}
